package cn.iocoder.yudao.module.diy.service.poster;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.diy.GetPosterParam;
import cn.iocoder.yudao.module.diy.PosterInitParam;
import cn.iocoder.yudao.module.diy.PosterModifyParam;
import cn.iocoder.yudao.module.diy.PreviewPosterParam;
import cn.iocoder.yudao.module.diy.compoent.EventAndSubscribeOfPublisher;
import cn.iocoder.yudao.module.diy.dal.diy.PosterTypeEnum;
import cn.iocoder.yudao.module.diy.exception.CommonException;
import cn.iocoder.yudao.module.diy.loader.JsonModuleLoader;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.freewayso.image.combiner.ImageCombiner;
import com.freewayso.image.combiner.enums.OutputFormat;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;

import cn.iocoder.yudao.module.diy.controller.admin.poster.vo.*;
import cn.iocoder.yudao.module.diy.dal.dataobject.poster.PosterDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import cn.iocoder.yudao.module.diy.dal.mysql.poster.PosterMapper;

import java.awt.*;
import java.io.File;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.diy.enums.ErrorCodeConstants.*;

/**
 * 装修海报 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class PosterServiceImpl implements PosterService {

    @Resource
    private PosterMapper posterMapper;

    @Override
    public Long createPoster(PosterSaveReqVO createReqVO) {
        // 插入
        PosterDO poster = BeanUtils.toBean(createReqVO, PosterDO.class);
        poster.setSiteId(TenantContextHolder.getTenantId());
        posterMapper.insert(poster);
        // 返回
        return poster.getId();
    }

    @Override
    public void updatePoster(PosterSaveReqVO updateReqVO) {
        // 校验存在
        validatePosterExists(updateReqVO.getId());
        // 更新
        PosterDO updateObj = BeanUtils.toBean(updateReqVO, PosterDO.class);
        posterMapper.updateById(updateObj);
    }

    @Override
    public void deletePoster(Long id) {
        // 校验存在
        validatePosterExists(id);
        // 删除
        posterMapper.deleteById(id);
    }

    private void validatePosterExists(Long id) {
        if (posterMapper.selectById(id) == null) {
            throw exception(POSTER_NOT_EXISTS);
        }
    }

    @Override
    public PosterDO getPoster(Long id) {
        return posterMapper.selectById(id);
    }

    @Override
    public PageResult<PosterDO> getPosterPage(PosterPageReqVO pageReqVO) {
        return posterMapper.selectPage(pageReqVO);
    }

    @Override
    public PosterInitVo init(PosterInitParam param) {
        PosterInitVo vo = new PosterInitVo();
        BeanUtils.copyProperties(param, vo);

        if (ObjectUtil.isNotEmpty(param.getId()) && param.getId() > 0) {
            PosterDO poster = posterMapper.selectOne(
                    new QueryWrapper<PosterDO>()
                            .eq("id", param.getId())
                            .eq("site_id", TenantContextHolder.getTenantId()));
            Assert.notNull(poster, "海报不存在!");
            BeanUtils.copyProperties(poster, vo);
        }

        vo.setPosterType(PosterTypeEnum.getType(vo.getType()));
        if (ObjectUtil.isNotEmpty(vo.getPosterType()) && ObjectUtil.isEmpty(vo.getAddon())) vo.setAddon(vo.getPosterType().getStr("addon", ""));

        JSONObject components = JsonModuleLoader.build().mergeResultElement("poster/components.json");

        vo.setComponent(new JSONObject());
        for (String key : components.keySet()) {
            JSONObject item = components.getJSONObject(key);
            if (item.getJSONObject("list") == null || item.getJSONObject("list").keySet().size() == 0) {
                continue;
            }
            JSONArray support = ObjectUtil.defaultIfNull(item.getJSONArray("support"), new JSONArray());
            if (!key.equals(vo.getType()) && support.size() > 0 &&  !support.contains(vo.getType())) {
                continue;
            }
            vo.getComponent().put(key, item);
        }

        return vo;
    }

    @Override
    public JSONArray template(String addon, String type) {
        final JSONArray template = new JSONArray();
        if (ObjectUtil.isNotEmpty(addon)) {
            JSONArray coreTemplate = JsonModuleLoader.build().findResultSet("", "poster/template.json");
            coreTemplate.stream().forEach(e -> template.add(e));

            JSONArray addonTemplate = JsonModuleLoader.build().findResultSet(addon, "poster/template.json");
            addonTemplate.stream().forEach(e -> template.add(e));
        } else {
            JSONArray all = JsonModuleLoader.build().mergeResultSet("poster/template.json");
            all.stream().forEach(e -> template.add(e));
        }

        if (ObjectUtil.isNotEmpty(type) && template.size() > 0) {
            return CollUtil.filter(template, i -> {
                JSONObject item = (JSONObject) i;
                return item.getStr("type", "").equals(type);
            });
        }

        return template;
    }

    @Override
    public void edit(Long id, SysPosterParam editParam) {
        PosterDO model = posterMapper.selectOne(
                new QueryWrapper<PosterDO>()
                        .eq("id", id)
                        .eq("site_id", TenantContextHolder.getTenantId()));
        Assert.notNull(model, "海报不存在!");

        if (editParam.getIsDefault().equals(1)) {
            UpdateWrapper update = new UpdateWrapper<>();
            update.setSql("is_default = 0");
            update.eq("type", editParam.getType());
            update.eq("is_default", 1);
            update.eq("site_id", TenantContextHolder.getTenantId());
            posterMapper.update(null, update);
        }
        model.setUpdateTime(DateUtils.of( new Date()));
        BeanUtils.copyProperties(editParam, model);
        posterMapper.updateById(model);

    }


    /**
     * 修改自定义海报状态
     *
     * @param id
     * @param status
     */
    @Override
    public void modifyStatus(Integer id, Integer status) {
        PosterDO model = new PosterDO();
        model.setStatus(status);
        posterMapper.update(model, new QueryWrapper<PosterDO>().eq("id", id).eq("site_id",TenantContextHolder.getTenantId()));
    }
    /**
     * 将自定义海报修改为默认海报
     *
     * @param id
     */
    @Override
    public void modifyDefault(Integer id) {
        PosterDO model = posterMapper.selectOne(
                new QueryWrapper<PosterDO>()
                        .eq("id", id)
                        .eq("site_id", TenantContextHolder.getTenantId()));

        Assert.notNull(model, "海报不存在!");

        UpdateWrapper update = new UpdateWrapper<>();
        update.setSql("is_default = 0");
        update.eq("type", model.getType());
        update.eq("is_default", 1);
        update.eq("site_id", TenantContextHolder.getTenantId());
        posterMapper.update(null, update);

        PosterDO updateModel = new PosterDO();
        updateModel.setIsDefault(1);
        updateModel.setId(Long.valueOf( id));
        posterMapper.updateById(updateModel);
    }
    /**
     * 预览海报
     * @param param
     */
    @Override
    public String preview(PreviewPosterParam param) {
        GetPosterParam getPosterParam = new GetPosterParam();
        getPosterParam.setId(param.getId());
        getPosterParam.setType(param.getType());
        getPosterParam.setSiteId(TenantContextHolder.getTenantId());
        getPosterParam.setChannel(ObjectUtil.defaultIfNull(param.getChannel(), "h5"));
        Map<String, Object> posterParam = new HashMap<>();
        posterParam.put("mode", "preview");
        getPosterParam.setParam(posterParam);
        getPosterParam.setIsThrowException(true);
        return get(getPosterParam);
    }

    /**
     * 获取海报
     */
    @Override
    public String get(GetPosterParam param) {
        QueryWrapper query = new QueryWrapper<>();
        query.eq("site_id", param.getSiteId());
        query.eq("type", param.getType());
        query.eq("status", 1);
        query.last("limit 1");
        if (ObjectUtil.isNotEmpty(param.getId()) && param.getId() > 0) {
            query.eq("id", param.getId());
        } else {
            query.eq("is_default", 1);
        }
        PosterDO model = posterMapper.selectOne(query);

        try {
            // 海报模板
            JSONObject poster = new JSONObject();
            if (model == null) {
                JSONArray template = template("", param.getType());
                if (template.size() > 0) {
                    poster = template.getJSONObject(0).getJSONObject("data");
                }
            } else {
                poster = JSONUtil.parseObj(model.getValue());
            }

            // 获取海报数据
            GetPosterDataEventDefiner.GetPosterDataEvent event = new GetPosterDataEventDefiner.GetPosterDataEvent();
            event.setSiteId(param.getSiteId());
            event.addAppSign("core");
            event.setName("GetPosterDataEvent");
            event.setType(param.getType());
            event.setParam(param.getParam());
            event.setChannel(param.getChannel());
            List<GetPosterDataEventDefiner.GetPosterDataResult> eventData = EventAndSubscribeOfPublisher.publishAndCallback(event);
            if (eventData.size() == 0) throw new CommonException("未获取到海报数据");

            GetPosterDataEventDefiner.GetPosterDataResult posterData = eventData.get(0);

            String dir = "upload/poster/" + param.getSiteId() + "/";
            String posterName = "poster_" + SecureUtil.md5(poster.toString()) + "_" + SecureUtil.md5(JSONUtil.parseObj(posterData).toString()) + "_" + param.getChannel() + ".png";

            if (new File(WebAppEnvs.get().webRootDownResource, dir + posterName).exists()) {
                return dir + posterName;
            }

            // 绘制海报
            create(param.getSiteId(), poster, posterData.getData(), dir, posterName);
            return dir + posterName;
        } catch (Exception e) {
            System.out.println("海报生成错误");
            e.printStackTrace();
            if (param.getIsThrowException()) throw new CommonException(e.getMessage());
            return "";
        }
    }

    /**
     * 绘制海报
     *
     * @param poster
     * @param posterData
     */
    private void create(Long siteId, JSONObject poster, Map<String, Object> posterData, String dir, String posterName) throws Exception
    {
        ImageCombiner combiner = null;
        if (poster.getByPath("global.bgType", String.class).equals("color")) {
            int width = poster.getByPath("global.width", int.class);
            int height = poster.getByPath("global.height", int.class);
            String bgColor = poster.getByPath("global.bgColor", String.class);
            combiner = new ImageCombiner(width, height, Color.decode(bgColor), OutputFormat.PNG);
        } else {
            String bfgUrl = poster.getByPath("global.bgUrl", String.class);
            combiner = new ImageCombiner(ImageUtils.readImage(bfgUrl), OutputFormat.PNG);
        }

        JSONArray items = poster.getJSONArray("value");
        for (int i = 0; i < items.size(); i++) {
            JSONObject item = items.getJSONObject(i);

            PosterDrawEvent event = new PosterDrawEvent();
            event.setSiteId(siteId);
            event.setName("PosterDrawEvent");
            event.setCombiner(combiner);
            event.setPoster(item);
            event.setPosterData(posterData);
            EventAndSubscribeOfPublisher.publishAll(event);
        }

        // 图片合成
        combiner.combine();

        FileTools.createDirs(new File(WebAppEnvs.get().webRootDownResource, dir).getPath());

        combiner.save(new File(WebAppEnvs.get().webRootDownResource, dir + posterName).getPath());
    }

}